#include "Contain.h"
#include <stdio.h>

CContainFactory ContainFactory;

#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
        EXTERN_C __declspec(selectany) const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
MIDL_DEFINE_GUID(CLSID, CLSID_AGGREGATE,0xC07AB602,0x53E8,0x4CFA,0xB3,0x7A,0x6F,0x9B,0xC0,0xF1,0xF4,0x91);

//////////////////////////////////////////////////////////////////
//  CContain
//////////////////////////////////////////////////////////////////

CContain::CContain() : m_dwRefCnt(0)
{
    CoCreateInstance(CLSID_AGGREGATE, &m_xContain, CLSCTX_INPROC_SERVER, 
        IID_IUnknown, (void**)&m_lpAggregateUnknown);

    ContainFactory.LockServer(TRUE);
}

CContain::~CContain()
{
    ContainFactory.LockServer(FALSE);
}

ULONG __stdcall CContain::XContain::AddRef()
{
    METHOD_PROLOGUE(CContain, Contain);
    pThis->m_dwRefCnt++;
    return pThis->m_dwRefCnt;
}

ULONG __stdcall CContain::XContain::Release()
{
    METHOD_PROLOGUE(CContain, Contain);

    if (pThis->m_dwRefCnt > 0)
        pThis->m_dwRefCnt--;

    if (pThis->m_dwRefCnt == 0)
    {
        printf("Release CContain\r\n");
        pThis->m_lpAggregateUnknown->Release();
        delete pThis;
    }
    return pThis->m_dwRefCnt;
}

HRESULT __stdcall CContain::XContain::QueryInterface(REFIID iid, void** ppvObj)
{
    METHOD_PROLOGUE(CContain, Contain);

    if (!ppvObj)
        return E_POINTER;

    *ppvObj = nullptr;

    if (iid == IID_IUnknown)
    {
        *ppvObj = this;
    }
    else if (iid == IID_IContain)
    {
        *ppvObj = &(pThis->m_xContain);
    }
    else if (iid == IID_IAggregate)
    {
        return pThis->m_lpAggregateUnknown->QueryInterface(IID_IAggregate, (void**)ppvObj);
    }

    if (*ppvObj)
    {
        ((IUnknown*)*ppvObj)->AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}

HRESULT __stdcall CContain::XContain::ContainTest()
{
    printf("CContain::Test\r\n");
    return S_OK;
}


//////////////////////////////////////////////////////////////////
//  CContainFactory
//////////////////////////////////////////////////////////////////

CContainFactory::CContainFactory()
{
}

CContainFactory::~CContainFactory()
{
}

HRESULT __stdcall CContainFactory::CreateInstance(
    IN OPTIONAL IUnknown* pUnkOuter,
    IN REFIID riid,
    OUT void** ppvObject
)
{
    CContain* lpContain = new CContain;
    return lpContain->m_xContain.QueryInterface(riid, ppvObject);
}

HRESULT __stdcall CContainFactory::LockServer(IN BOOL fLock)
{
    if (fLock)
    {
        InterlockedIncrement(&m_nLockTick);
    }
    else
    {
        if (m_nLockTick > 0)
            InterlockedDecrement(&m_nLockTick);
    }

    return S_OK;
}
